package ncme.auto.framework.core.typeHandler.primaryTypeHandlers;

import com.alibaba.fastjson.JSONArray;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

public class CollectionTypeHandler<T extends Collection<?>> extends BaseTypeHandler<T> {

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, T parameter, JdbcType jdbcType) throws SQLException {
        preparedStatement.setString(i, JSONArray.toJSONString(parameter));
    }

    @Override
    public T getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return getListFromJsonString(resultSet.getString(s));
    }

    private T getListFromJsonString(String jsonString) {
        JSONArray jsonArray = JSONArray.parseArray(jsonString);
        Class<?> objectClass = getObjectClass();
        List res = JSONArray.parseArray(jsonString, objectClass);
        Class<?> collectionClass = getCollectionClass();
        String typeName = collectionClass.getTypeName();
        if (typeName.equals("java.util.List")) {
            return (T) res;
        } else if (typeName.equals("java.util.Set")) {
            HashSet hashSet = new HashSet<>(res);
            return (T) hashSet;
        }
        return (T) new Object();
    }

    private Class<?> getObjectClass() {
        //拿到该类的类型
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            //拿到T类型
            ParameterizedType parameterizedType_This = (ParameterizedType) type;
            Type collectionType = parameterizedType_This.getActualTypeArguments()[0];
            //拿到T类型的泛型类型
            ParameterizedType parameterizedType_Collection = (ParameterizedType) collectionType;
            Type objectType = parameterizedType_Collection.getActualTypeArguments()[0];
            return (Class<?>) objectType;
        }
        throw new RuntimeException();
    }

    private Class<?> getCollectionClass() {
        //拿到该类的类型
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            //拿到T类型
            ParameterizedType parameterizedType_This = (ParameterizedType) type;
            Type collectionType = parameterizedType_This.getActualTypeArguments()[0];
            ParameterizedType parameterizedType_Collection = (ParameterizedType) collectionType;
            return (Class<?>) parameterizedType_Collection.getRawType();
        }
        throw new RuntimeException();
    }

    @Override
    public T getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return getListFromJsonString(resultSet.getString(i));
    }

    @Override
    public T getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return getListFromJsonString(callableStatement.getString(i));
    }

    //序列化为字符串
    private String serializeObject(Object object) throws Exception {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteArrayOutputStream);
        out.writeObject(object);
        //必须是ISO-8859-1
        String objectStr = byteArrayOutputStream.toString("ISO-8859-1");
        out.close();
        byteArrayOutputStream.close();
        return objectStr;
    }

    //反序列化为对象
    public Object stringSerializeObject(String objectStr) throws Exception {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(objectStr.getBytes(StandardCharsets.ISO_8859_1));
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        Object object = objectInputStream.readObject();
        objectInputStream.close();
        byteArrayInputStream.close();
        return object;
    }
}

